package com.naiterui.ehp.bs.patient.controller;

import com.naiterui.common.redis.RedisUtil;
import com.naiterui.ehp.bp.constants.SwaggerTag;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bp.utils.date.DateUtil;
import com.naiterui.ehp.bp.utils.encypt.GengerCode;
import com.naiterui.ehp.bp.utils.lang.StringUtil;
import com.naiterui.ehp.bs.patient.exception.ExceptionCodes;
import com.naiterui.ehp.bs.patient.service.IPatientService;
import com.naiterui.ehp.bs.patient.utils.SMSUtil;
import com.naiterui.ehp.bs.patient.utils.SMSUtil.Template;
import com.naiterui.ehp.bs.patient.utils.cache.CommonCacheUtil;
import com.naiterui.ehp.bs.patient.utils.constants.PatientConstant;
import com.naiterui.ehp.bs.patient.vo.CodeVO;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;

/**
 * 短信接口
 *
 * @version 2015年6月27日 上午1:03:51 by Amber
 */
@Api(tags = SwaggerTag.PATIENT + SwaggerTag.USER_ACCOUNT)
@RequestMapping("ap/sms")
@Controller
public class ApSendSMSController {
    private static final Logger LOGGER = LoggerFactory.getLogger(ApSendSMSController.class);

    private static final int SMS_CACHE_TIME = 60 * 10;

    @Autowired
    private IPatientService patientService;

    /**
     * 发送验证码
     *
     * @param phoneNum   患者输入手机号码
     * @param actionType 功能类型(0/完善信息；1/修改手机号；2：其他验证)
     *
     * @return
     */
    @ResponseBody
    @RequestMapping(value = "/send")
    @ApiOperation(value = "", httpMethod = "POST", produces = MediaType.APPLICATION_JSON_VALUE)
    public void sendSMs(String phoneNum, Integer actionType) throws BusinessException {
        LOGGER.info("sms send PARAM-INFO ; phoneNum {},actionType {}", phoneNum, actionType);
        if (actionType == null || StringUtils.isEmpty(phoneNum)) {
            // 异常日志
            LOGGER.error("sms send ERROR ; illegal param : actionType {}, phoneNum {}", actionType, phoneNum);
            throw new BusinessException(actionType == null ? ExceptionCodes.SMS_PHONE_ACT_ERROR : ExceptionCodes.SMS_PHONE_NULL);
        }

        // 手机号格式校验
        if (!StringUtil.isMobileNum(phoneNum)) {
            // 手机号格式错误
            LOGGER.error("sms send ERROR ; illegal phoneNum format : actionType {}, phoneNum {}", actionType, phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ERROR);
        }

        if (actionType == 0 || actionType == 1) {
            // 手机号已经绑定
            if (!this.patientService.unionValidate(phoneNum)) {
                // 日志记录
                LOGGER.error("sms send ERROR ; sms phone has binded : phoneNum {}, actionType {}", phoneNum, actionType);
                throw new BusinessException(ExceptionCodes.PATIENT_PHONE_EXIST);
            }
        }

        // 频率校验，每60秒发一次

        if (RedisUtil.keyOps().existsKey(CommonCacheUtil.getCodeTimestampKey(actionType, phoneNum))) {
            // 日志记录
            LOGGER.error("sms send ERROR ; sms send too frequent : phoneNum {},actionType {}", phoneNum, actionType);
            throw new BusinessException(ExceptionCodes.SMS_MAX_FREQUENCY);
        }

        // 次数校验，每天上限10次
        String date = DateUtil.formatDate(new Date(), DateUtil.DATE_FORMAT);
        Long times = RedisUtil.keyOps().incr(CommonCacheUtil.getPhoneCodeTimesKey(phoneNum, actionType, date));
        if (times != null && times > PatientConstant.SMS_DAY_MAX) {
            // 日志记录
            LOGGER.error("sms send ERROR ; sms has send max times per day : phoneNum {}, actionType {}", phoneNum, actionType);
            throw new BusinessException(ExceptionCodes.SMS_MAX_COUNT);
        }

        // 短信内容
        Template tmpl = null;
        if (actionType == 0 || actionType == 1 || actionType == 2) {// 添加手机号,修改手机号
            tmpl = Template.VERIFICATION_CODE_TEMPLATE;
        } else {
            // 不支持的操作类型
            LOGGER.error("sms send ERROR ; sms actionType {} is not supported : phoneNum {}", actionType, phoneNum);
            throw new BusinessException(ExceptionCodes.SMS_PHONE_ACT_ERROR);
        }

        // 缓存中获取验证码信息
        CodeVO codeInfo = CommonCacheUtil.getCodeInfoFromRedis(actionType, phoneNum);
        String code = "";
        // 缓存内没有验证码信息，或验证码创建时间已超10分钟，重新生成验证码覆盖旧验证码
        if (codeInfo == null || (System.currentTimeMillis() - codeInfo.getCreatedAt().getTime() > SMS_CACHE_TIME * 1000)) {
            // 随机验证码
            code = GengerCode.generateSmsCode();

            // 缓存验证码，同时更新手机号验证码时间戳。
            CommonCacheUtil.setCodeToRedis(actionType, phoneNum, code, SMS_CACHE_TIME);
        } else {
            // 缓存有验证码信息，且发送时间在10分钟内，不更新验证码，延长使用有效期
            code = CommonCacheUtil.getCodeFromRedis(actionType, phoneNum);
            CommonCacheUtil.updateCodeEffectiveTime(actionType, phoneNum, SMS_CACHE_TIME);
        }
        // 调用远程接口，发送验证码
        SMSUtil.sendSMS(phoneNum, tmpl, code);
    }

}
